package com.springboot.tools.toolkit;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.k.mybatisplus.annotations.TableField;
import com.k.mybatisplus.annotations.TableId;
import com.k.mybatisplus.annotations.TableName;

/**
 * * @ClassName: TableInfoHelper
 * 
 * @Description: TODO(ʵ���෴�������)
 * @author KXD
 * @date 2016��3��28�� ����1:43:38
 */
public class TableInfoHelper
{
    // ���淴�������Ϣ
    private static Map<String, TableInfo> tableInfoCache = new ConcurrentHashMap<String, TableInfo>();

    // ����ʵ���෴���ȡ����Ϣ
    public synchronized static TableInfo getTableInfo(Class<?> clazz)
    {
        TableInfo ti = tableInfoCache.get(clazz.getName());
        if (ti != null)
        {
            return ti;
        }
        List<Field> list = getAllFields(clazz);
        TableInfo tableInfo = new TableInfo();

        // ����
        TableName table = clazz.getAnnotation(TableName.class);
        if (table != null && table.value() != null
                && table.value().trim().length() > 0)
        {
            tableInfo.setTableName(table.value());
        }
        else
        {
            tableInfo.setTableName(camelToUnderline(clazz.getSimpleName()));
        }
        List<TableFieldInfo> fieldList = new ArrayList<TableFieldInfo>();
        for (Field field : list)
        {
            // ����ID
            TableId tableId = field.getAnnotation(TableId.class);
            if (tableId != null)
            {
                tableInfo.setIdType(tableId.type());
                if (tableId.value() != null && !"".equals(tableId.value()))
                {
                    // �Զ����ֶ���
                    tableInfo.setKeyColumn(tableId.value());
                    tableInfo.setKeyRelated(true);
                }
                else
                {
                    tableInfo.setKeyColumn(field.getName());
                }
                tableInfo.setKeyProperty(field.getName());
                continue;
            }

            // ��ȡע�����ԣ��Զ����ֶ�
            TableField tableField = field.getAnnotation(TableField.class);
            if (tableField != null && tableField.value() != null
                    && !"".equals(tableField.value()))
            {
                fieldList.add(new TableFieldInfo(true, tableField.value(),
                        field.getName()));
                continue;
            }
            // �ֶ�
            fieldList.add(new TableFieldInfo(field.getName()));

        }
        // �ֶ��б�
        tableInfo.setFieldList(fieldList);
        tableInfoCache.put(clazz.getName(), tableInfo);
        return tableInfo;
    }

    private static String camelToUnderline(String param)
    {
        if (param == null || "".equals(param.trim()))
        {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++)
        {
            char c = param.charAt(i);
            if (Character.isUpperCase(c))
            {
                sb.append("_");
                sb.append(Character.toLowerCase(c));
            }
            else
            {
                sb.append(Character.toLowerCase(c));
            }
        }
        return sb.toString();

    }

    // ��ȡ��������������б�
    private static List<Field> getAllFields(Class<?> clazz)
    {
        List<Field> result = new LinkedList<Field>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields)
        {
            // ����transient �ؼ������εĸ�����
            if (Modifier.isTransient(field.getModifiers()))
            {
                continue;
            }
            // ����ע��Ǳ��ֶ�����
            TableField tableField = field.getAnnotation(TableField.class);
            if (tableField == null || tableField.exist())
            {
                result.add(field);
            }
        }
        // �������ֶ�
        Class<?> superClass = clazz.getSuperclass();
        if (superClass.equals(Object.class))
        {
            return result;
        }
        result.addAll(getAllFields(superClass));
        return result;
    }

}
